package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.message.PublishArticleConstants;
import com.heima.common.constants.wemedia.NewsAutoScanConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFegin;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author lo
 * @date 2021/9/25
 * 自动审核功能
 */
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {
    @Autowired
    AdminFegin adminFegin;

    @Autowired
    WmNewsMapper wmNewsMapper;

    /**
     * 阿里云文本校验
     */
    @Autowired
    private GreenTextScan greenTextScan;

    /**
     * 阿里云图片校验
     */
    @Autowired
    private GreenImageScan greenImageScan;

    /**
     * 图片访问前缀
     */
    @Value("${file.oss.web-site}")
    String site;

    /**
     * 发布文章
     * 发送消息给交换机
     */
    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 实现自动审核
     *
     * @param id 自媒体文章id
     */
    @Override
    public void autoScanWmNews(Integer id) {
        //1.校验参数
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //2.根据id查询对应的文章信息
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "对应的文章不存在");
        }
        //3.判断状态是否为1(待审核)
        if (!wmNews.getStatus().equals(WemediaConstants.WM_NEWS_SINGLE_IMAGE)) {
            return;
        }
        //4.抽取所有文本和图片
        Map<String, Object> allMsg = handleTextAndImages(wmNews);

        //5.DFA敏感词文本核验
        boolean sensitiveDFA = handleSensitive((String) allMsg.get("content"), wmNews);
        if (!sensitiveDFA) {
            //审核不通过
            return;
        }

        //6.阿里云文本校验
        boolean aLiYunText = AliyunCheckContent((String) allMsg.get("content"), wmNews);
        if (!aLiYunText) {
            //审核不通过
            return;
        }

        //7.阿里云图片校验
        List<String> image = (List<String>) allMsg.get("image");
        if (image != null) {
            boolean aliyunImage = AliyunCheckImage(image, wmNews);
            if (!aliyunImage) {
                return;
            }
        }
        //8.自动审核通过,改变文章状态
        updateWmNews(wmNews, WemediaConstants.WM_NEWS_AUTHED_STATUS, "自动审核通过");

        //9.TODO:开始发布文章信息
        // 获取发布时间的毫秒值
        Date publishTime = wmNews.getPublishTime();
        //装换为毫秒值
        long publish = publishTime.getTime();

        //2.获取当前时间
        long time = System.currentTimeMillis();
        long remainTime =  publish- time;
        log.debug("开始发送发布文章的信息");
        if (remainTime>0){
            //说明文章还没到发布时间,延迟发送
            rabbitTemplate
                    .convertAndSend(
                            //指定交换机
                            PublishArticleConstants.PUBLISH_ARTICLE_EXCHANGE,
                            //指定routingKey
                            PublishArticleConstants.PUBLISH_ARTICLE_DEAD_ROUTE_KEY,
                            //发送的信息
                            wmNews.getId(),
                            //设定延迟时间
                            (message) -> {
                        message.getMessageProperties().setExpiration(String.valueOf(remainTime));
                        return message;
                    });
            log.debug("延时发布文章通知成功发送，文章id : {} , 延时时间: {}毫秒",wmNews.getId(),remainTime);
        }else {
            //说明文章的发布时间已经到达,设置延迟时间为0
            rabbitTemplate.convertAndSend(
                    PublishArticleConstants.PUBLISH_ARTICLE_EXCHANGE,
                    PublishArticleConstants.PUBLISH_ARTICLE_DEAD_ROUTE_KEY,
                    wmNews.getId(),
                    message -> {
                        message.getMessageProperties().setExpiration("0");
                        return message;
                    }
            );
            log.debug("发布文章通知成功发送，不延时,文章id : {} , 延时时间: {}毫秒",wmNews.getId(),remainTime);
        }

    }

    /**
     * 阿里云校图片
     *
     * @param image  图片集合
     * @param wmNews 文章
     * @return bool true: 通过  false: 不通过
     */
    private boolean AliyunCheckImage(List<String> image, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenImageScan.imageUrlScan(image);
            String suggestion = (String) map.get("suggestion");

            //判断状态
            switch (suggestion) {
                case "block":
                    updateWmNews(wmNews, WemediaConstants.WM_NEWS_FAIL_STATUS, "阿里云审核失败");
                    flag = false;
                    break;
                case "review":
                    updateWmNews(wmNews, WemediaConstants.WM_NEWS_MANPOWER_STATUS, "阿里云不确定,转为人工审核");
                    flag = false;
                    break;
            }
        } catch (Exception e) {
            log.error("阿里云校图片失败,转为人工审核,错误原因: {}", e.getMessage());
            updateWmNews(wmNews, WemediaConstants.WM_NEWS_MANPOWER_STATUS, "阿里云不确定,转为人工审核");
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 通过 阿里云审核文本
     *
     * @param content 文本信息
     * @param wmNews  文章信息
     * @return bool true: 通过  false: 不通过
     */
    private boolean AliyunCheckContent(String content, WmNews wmNews) {
        boolean flag = true;
        Map map = null;
        try {
            map = greenTextScan.greenTextScan(content);

            String suggestion = (String) map.get("suggestion");
            //判断状态
            switch (suggestion) {
                case "block":
                    updateWmNews(wmNews, WemediaConstants.WM_NEWS_FAIL_STATUS, "阿里云审核失败");
                    flag = false;
                    break;
                case "review":
                    updateWmNews(wmNews, WemediaConstants.WM_NEWS_MANPOWER_STATUS, "阿里云不确定,转为人工审核");
                    flag = false;
                    break;
            }
        } catch (Exception e) {
            log.error("阿里云远程校文本失败,转为人工审核,原因:{}", e.getMessage());
            updateWmNews(wmNews, WemediaConstants.WM_NEWS_MANPOWER_STATUS, "阿里云不确定,转为人工审核");
            e.printStackTrace();

        }
        return flag;
    }

    /**
     * 修改文章状态
     *
     * @param wmNews 文章
     * @param status 状态
     * @param reason 原因
     */
    private void updateWmNews(WmNews wmNews, Short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 基于DFA 检测内容是否包含敏感词
     *
     * @param content 文本
     * @param wmNews  文章
     * @return bool true: 通过  false: 不通过
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;
        //5.1远程调用敏感词查询接口
        ResponseResult<List<String>> sensitives = adminFegin.sensitives();
        if (sensitives.getCode() != 0) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, "远程调用敏感词查询失败");
        }
        List<String> sensitivesList = sensitives.getData();

        SensitiveWordUtil.initMap(sensitivesList);
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);

        if (map != null && map.size() > 0) {
            //说明命中了敏感词
            // 更新文章状态
            updateWmNews(wmNews, WemediaConstants.WM_NEWS_FAIL_STATUS, "文本包含敏感词");
            log.debug("内容审核未通过   文章id:{}      未通过原因: 包含敏感词{}", wmNews.getId(), content);
            flag = false;
        }
        return flag;
    }

    /**
     * 抽取  文章中所有  文本  及  图片
     *
     * @param news 文本信息
     * @return map {   content :       images:  }
     */
    private Map<String, Object> handleTextAndImages(WmNews news) {
        //4.抽取文章中的所有文本信息以及图片信息
        HashMap<String, Object> result = new HashMap<>(8);
        String content = news.getContent();
        List<Map> mapList = JSON.parseArray(content, Map.class);
        //4.1抽取文本信息并用_heh_连接
        String textAry = mapList.stream().filter(map -> "text".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.joining("_heh_"));
        //将文章标题拼接
        textAry += textAry + "_heh_" + news.getTitle();

        result.put("content", textAry);

        //4.2 抽取 所有文章图片信息
        List<String> imageList = mapList.stream().filter(map -> "image".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.toList());

        //4.3 抽取所有封面
        String images = news.getImages();
        if (StringUtils.isNotBlank(images)) {
            List<String> collect = Arrays.stream(images.split(","))
                    .map(map -> site + map)
                    .collect(Collectors.toList());
            //整合图片集合
            imageList.addAll(collect);
        }
        //添加
        // 2.3  去重
        imageList = imageList.stream().distinct().collect(Collectors.toList());
        result.put("image", imageList);
        return result;
    }
}
